using ColorFillGame.Domain.Exceptions;
using ColorFillGame.Domain.ValueObjects;

namespace ColorFillGame.Domain.Entities;

public enum GameStatus
{
    Created,
    InProgress,
    Completed
}

public class Game : IAggregateRoot
{
    public Guid Id { get; private set; }
    public string Name { get; private set; }
    public GameStatus Status { get; private set; }
    public DateTime CreatedAt { get; private set; }
    public DateTime? StartedAt { get; private set; }
    public DateTime? CompletedAt { get; private set; }
    public int GridSize { get; private set; }
    public int MaxPlayers { get; private set; }
    public List<Player> Players { get; private set; }
    public GameGrid Grid { get; private set; }
    public Guid? WinnerId { get; private set; }

    private Game()
    {
        // EF Core constructor
        Players = new List<Player>();
    }

    public Game(Guid id, string name, int gridSize, int maxPlayers)
    {
        Id = id;
        Name = name;
        GridSize = gridSize;
        MaxPlayers = maxPlayers;
        Status = GameStatus.Created;
        CreatedAt = DateTime.UtcNow;
        Players = new List<Player>();
        Grid = new GameGrid(gridSize);
    }

    public void AddPlayer(Player player)
    {
        if (Status != GameStatus.Created)
            throw new DomainException("Cannot add players to a game that has already started.");
        
        if (Players.Count >= MaxPlayers)
            throw new DomainException("Game room is full.");
        
        if (Players.Any(p => p.Id == player.Id))
            throw new DomainException("Player already exists in the game.");
        
        Players.Add(player);
        
        // Assign a color to the player if not already assigned
        if (player.Color == null)
        {
            var availableColors = PlayerColor.GetAvailableColors();
            var usedColors = Players.Where(p => p.Color != null).Select(p => p.Color.Name).ToList();
            var availableColor = availableColors.FirstOrDefault(c => !usedColors.Contains(c));
            
            if (availableColor != null)
            {
                player.SetColor(PlayerColor.FromName(availableColor));
                Console.WriteLine($"Assigned color {availableColor} (Hex: {player.Color.HexCode}) to player {player.Name}");
            }
            else
            {
                Console.WriteLine($"No available colors for player {player.Name}");
            }
        }
    }

    public void RemovePlayer(Guid playerId)
    {
        var player = Players.FirstOrDefault(p => p.Id == playerId);
        if (player != null)
        {
            Players.Remove(player);
            
            // If the game was in progress but all players left, mark as completed
            if (Status == GameStatus.InProgress && Players.Count == 0)
            {
                CompleteGame();
            }
        }
    }

    public void StartGame()
    {
        if (Status != GameStatus.Created)
            throw new DomainException("Game has already started.");
        
        if (Players.Count < 2)
            throw new DomainException("At least 2 players are required to start the game.");
        
        Status = GameStatus.InProgress;
        StartedAt = DateTime.UtcNow;
    }

    public void CompleteGame()
    {
        if (Status != GameStatus.InProgress)
            throw new DomainException("Game is not in progress.");
        
        Status = GameStatus.Completed;
        CompletedAt = DateTime.UtcNow;
    }

    public void ApplyPaintAction(Player player, Position position)
    {
        // 暂时放宽状态检查，允许Created状态下也能涂色用于调试
        if (Status != GameStatus.InProgress && Status != GameStatus.Created)
            throw new DomainException($"Game is not in progress or created. Current status: {Status}");
        
        if (!Players.Contains(player))
            throw new DomainException("Player is not part of this game.");
        
        if (player.Color == null)
            throw new DomainException("Player does not have a color assigned.");
        
        // Check if the position is valid
        if (!position.IsValid(GridSize))
            throw new DomainException("Invalid position.");
        
        Console.WriteLine($"Applying paint action: Player={player.Name}, Color={player.Color.Name}, Position=({position.X},{position.Y})");
        
        // Apply the paint action
        Grid.FillPosition(position, player.Color);
        
        // Only check win condition if game is actually in progress
        if (Status == GameStatus.InProgress && CheckWinCondition(player))
        {
            CompleteGame();
        }
    }

    private bool CheckWinCondition(Player player)
    {
        // This is a simplified win condition check
        // In a real implementation, you would check if the player has filled a significant portion of the grid
        // or if they have connected their starting position to all edges, etc.
        var filledCells = Grid.GetFilledCellsByColor(player.Color);
        var totalCells = GridSize * GridSize;
        
        // For example, if a player has filled 50% of the grid
        return (double)filledCells.Count / totalCells >= 0.5;
    }
}

public interface IAggregateRoot
{
    // Marker interface
}